#include<iostream>
#include<signal.h>
#include<unistd.h>
#include<sys/types.h>
#include<stdio.h>

// void WaitAll(int num)
// {
//     while (true)
//     {
//         pid_t n = waitpid(-1, nullptr, WNOHANG); // 阻塞了！
//         if (n == 0)
//         {
//             break;
//         }
//         else if (n < 0)
//         {
//             std::cout << "waitpid error " << std::endl;
//             break;
//         }
//     }
//     // while (true)
//     // {
//     //     pid_t n = waitpid(-1, nullptr, WNOHANG); // waitpid默认是阻塞的！
// //waitpid(-1, nullptr, WNOHANG)	父进程主动循环查询，回收退出的子进程
// 	//需要获取子进程退出状态（比如退出码、终止信号
//     //     if (n == 0)
//     //     {
//     //         break;
//     //     }
//     //     else if (n < 0)
//     //     {
//     //         std::cout << "waitpid error " << std::endl;
//     //         break;
//     //     }
//     // }

//     std::cout << "father get a signal: " << num << std::endl;
// }
// WaitAll 函数，原本是「父进程主动调用 waitpid 非阻塞回收所有子进程」
// —— 这是「主动回收」的方式；而本程序用 signal(SIGCHLD, SIG_IGN) 是「被动自动回收」的方式。

int main()
{
    // 父进程
    signal(SIGCHLD, SIG_IGN); // 父进程
    //父进程忽略信号，内核自动回收
    //不需要子进程退出状态，简单高效
    for (int i = 0; i < 10; i++)
    {
        pid_t id = fork(); // 如果我们有10个子进程呢？？6退出了，4个没退
        if (id == 0)
        {
            sleep(3);
            std::cout << "I am child, exit" << std::endl;
            exit(3);
            // if(i <= 6) exit(3);
            // else pause();
        }
    }

    while (true)
    {
        std::cout << "I am fater, exit" << std::endl;
        sleep(1);
    }

    return 0;
}

// volatile int flag = 0;
// // 不加 volatile 时，编译器的优化逻辑：
// // 循环 while (!flag) 里没有任何 “修改 flag” 的代码（用户态视角）；
// // 编译器认为 flag 是 “不变的”，为了提高效率，会把 flag 缓存到 CPU 寄存器 中；
// // 循环每次判断 !flag 时，都直接读寄存器里的旧值（0），而不是去内存中读 handler 修改后的新值（1）；
// // 所以即使 handler 改了内存中的 flag，循环依然读寄存器的旧值，陷入死循环。
// // 加 volatile 时，编译器的行为：
// // volatile 的字面意思是 “易变的”，它告诉编译器：
// // 这个变量可能被 “当前代码之外的因素” 修改（比如信号处理函数、线程、硬件）；
// // 禁止把变量缓存到寄存器，每次访问都必须去 内存中读取原始值；
// // 所以循环每次判断 !flag 时，都会去内存读 flag，能立即看到 handler 修改后的新值（1），循环退出。
// void handler(int signum)
// {
//     std::cout << "更改全区变量" << flag << "-> -1" << std::endl;
//     flag = 1;
// }


// int main()
// {
//     signal(2, handler);
//     while(!flag)
//     {
//         printf("醉了偶\n");//std::cout << "process quit normal!" << std::endl;
//     }
//     return 0;
// }






// void handler(int signum)
// {
//     std::cout << "hello, signal: " << signum << std::endl;
//     while(true)
//     {
//         //不断获取pending表
//         sigset_t pending;
//         sigpending(&pending);
//         for(int i = 31; i >= 1; i--)
//         {
//             if(sigismember(&pending, i))
//                 std::cout << "1";
//             else
//                 std::cout << "0";
//         }
//         std::cout << std::endl;
//         sleep(1);
//     }
//     exit(0);
// }
// // 实现了一个 “信号处理 + 未决信号监控” 的完整演示：
// // sigaction 配置：给 SIGINT 注册 handler，并在处理期间屏蔽信号 2、3、4；
// // 收到 SIGINT 后，handler 启动，持续打印未决信号集；
// // 发送被屏蔽的信号（2、3、4），能在打印结果中看到这些信号进入 “未决态”（对应位变 1）；
// // 直到 handler 退出（但这段代码是死循环，所以会一直监控）。
// // 总结：这段 handler 代码是 **“未决信号集” 的可视化工具 **，结合 sigaction 的阻塞配置
// // ，能让你直观理解 “信号产生→阻塞→未决” 的整个流程。

// int main()
// {
//     struct sigaction act, oact;
//     act.sa_handler = handler;
//     sigemptyset(&act.sa_mask);
//     sigaddset(&act.sa_mask,3);
//     //sigaddset(&act.sa_mask,3);
//     act.sa_flags = 0;

//     sigaction(SIGINT, &act, &oact);//对2号信号进行捕捉

//     while(true)
//     {
//         std::cout << "hello world: " << getpid() << std::endl;
//         sleep(1);
//     }
//     return 0;
// }

